package com.codeoss.framework.report.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.codeoss.framework.context.YunContext;
import com.codeoss.framework.converter.IConverter;
import com.codeoss.framework.converter.IConverterStore;
import com.codeoss.framework.data.metadata.Column;
import com.codeoss.framework.data.metadata.Query;
import com.codeoss.framework.data.metadata.Restrictions;
import com.codeoss.framework.data.metadata.Table;
import com.codeoss.framework.data.metadata.TableData;
import com.codeoss.framework.data.store.ITableStore;
import com.codeoss.framework.expression.Expression;
import com.codeoss.framework.expression.ExpressionUtil;
import com.codeoss.framework.expression.JavaScriptScriptService;
import com.codeoss.framework.report.def.DetailReport;
import com.codeoss.framework.report.def.Field;
import com.codeoss.framework.report.def.FieldConditionStyle;
import com.codeoss.framework.util.LookupInfo;
import com.codeoss.framework.util.StringUtils;
import com.codeoss.framework.view.component.IDataBinding;
import com.codeoss.framework.view.component.IVarName;
import com.codeoss.framework.view.component.Page;
import com.codeoss.framework.view.datasource.DataSourceConfig;
import com.codeoss.framework.view.datasource.IDataSource;
import com.codeoss.framework.view.datasource.store.IDataSourceStore;
import com.codeoss.framework.view.model.SelectItem;
import com.codeoss.framework.view.service.IVariableService;
import com.codeoss.framework.view.util.LookupUtil;
import com.codeoss.module.ir.model.IrReport;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

@Component
public class DetailReportUtil {
	@Autowired
	private ObjectMapper objectMapper;
	@Autowired
	private ITableStore tableStore;
	@Autowired
	private IDataSourceStore dataSourceStore;
	@Autowired
	private JavaScriptScriptService javaScriptScriptService;
	@Autowired
	private LookupUtil lookupUtil;
	@Autowired
	private IConverterStore converterStore;
	@Autowired
	private IVariableService variableService;
	public DetailReport buildDetailReportFromIrReport(IrReport irReport) {
		String jsonContext=irReport.getJsonContent();
		if(!StringUtils.isEmpty(jsonContext)) {
			try {
				DetailReport detailReport=objectMapper.readValue(jsonContext, DetailReport.class);
				return detailReport;
			} catch (Exception e) {
				// TODO Auto-generated catch block
				throw new RuntimeException(e);
			}
		}
		return null;
	}
	
	public DetailReport buildDetailReportFromJson(String json) {
		ObjectNode objectNode = null;
		try {
			objectNode = (ObjectNode) objectMapper.readTree(json);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		}
		DetailReport detailReport = new DetailReport();
		DataSourceConfig dataSourceConfig = buildDataSourceConfig(objectNode);
		detailReport.setDataSourceConfig(dataSourceConfig);

		ArrayNode fieldListArrayNode = (ArrayNode) objectNode.get("displayFieldConfigPage").get("fieldList");
		List<Field> fieldList = new ArrayList<Field>();
		detailReport.setFieldList(fieldList);
		for (int i = 0; i < fieldListArrayNode.size(); i++) {
			ObjectNode fieldObjectNode = (ObjectNode) fieldListArrayNode.get(i);
			boolean display = fieldObjectNode.get("display").asBoolean();
			if (!display) {
				continue;
			}
			Field field = new Field();
			fieldList.add(field);
			field.setColumnName(fieldObjectNode.get("columnName").asText());
			field.setViewType(fieldObjectNode.get("viewType").asText());
			field.setName(fieldObjectNode.get("name").asText());
		}

		ArrayNode styleData = (ArrayNode) objectNode.get("fieldConditionStylePage").get("styleData");
		List<FieldConditionStyle> fieldConditionStyleList = new ArrayList<FieldConditionStyle>();
		detailReport.setFieldConditionStyleList(fieldConditionStyleList);
		for (int i = 0; i < styleData.size(); i++) {
			ObjectNode styleObjectNode = (ObjectNode) styleData.get(i);
			FieldConditionStyle fieldConditionStyle = new FieldConditionStyle();
			fieldConditionStyleList.add(fieldConditionStyle);
			String field = styleObjectNode.get("field").asText();
			String condition = styleObjectNode.get("condition").asText();
			String style = styleObjectNode.get("style").asText();
			fieldConditionStyle.setField(field);
			Expression conditionExpression = ExpressionUtil.convertToExpression(condition,
					Expression.EXPRESSION_TYPE_JAVASCRIPT);
			fieldConditionStyle.setCondition(conditionExpression);
			fieldConditionStyle.setStyle(style);
		}
		return detailReport;
	}

	private DataSourceConfig buildDataSourceConfig(ObjectNode objectNode) {
		DataSourceConfig dataSourceConfig = new DataSourceConfig();
		String id = objectNode.get("dataSourceConfigPage").get("id").asText();
		String name = objectNode.get("dataSourceConfigPage").get("name").asText();
		String tableName = objectNode.get("dataSourceConfigPage").get("tableName").asText();
		String whereClause = objectNode.get("dataSourceConfigPage").get("whereClause").asText();
		String orderBy = objectNode.get("dataSourceConfigPage").get("orderBy").asText();
		dataSourceConfig.setId(id);
		dataSourceConfig.setName(name);
		dataSourceConfig.setTableName(tableName);
		if (!StringUtils.isEmpty(whereClause)) {
			Expression expression = ExpressionUtil.convertToExpression(whereClause,
					Expression.EXPRESSION_TYPE_JAVASCRIPT);
			dataSourceConfig.setWhereClause(expression);
		}
		dataSourceConfig.setOrderBy(orderBy);
		return dataSourceConfig;
	}
	public DetailReportModel buildDetailReportData(DetailReport detailReport) {
		return buildDetailReportData(detailReport,1);
	}
	
	public DetailReportModel buildDetailReportData(DetailReport detailReport,int page) {
		DetailReportModel detailReportData = new DetailReportModel();
		YunContext yunContext = YunContext.getCurrentContext();
		TableData tableData = getTableData(yunContext, detailReport,page);
		if(tableData.getTotal()==0) {
			return null;
		}
		Map<String, List<SelectItem>> selectItemMap = new HashMap<String, List<SelectItem>>();
		Map<String, String> styleMap = new HashMap<String, String>();
		detailReportData.setTableData(tableData);
		detailReportData.setStyleMap(styleMap);
		List<Field> fieldList = detailReport.getFieldList();
		detailReportData.setFieldList(fieldList);
		Table table = tableStore.get(detailReport.getDataSourceConfig().getTableName());
		if (tableData.getTotal() > 0) {
			List<FieldConditionStyle> fieldConditionStyleList = detailReport.getFieldConditionStyleList();
			
			for (int i = 0; i < fieldConditionStyleList.size(); i++) {
				FieldConditionStyle fieldConditionStyle = fieldConditionStyleList.get(i);
				String field = fieldConditionStyle.getField();
				int index = -1;
				for (int j = 0; j < fieldList.size(); j++) {
					if (fieldList.get(j).equals(field)) {
						index = j;
						break;
					}
				}
				List<Map<String, Object>> dataList = tableData.getData();
				Expression condition = fieldConditionStyle.getCondition();
				String style = fieldConditionStyle.getStyle();
				if (condition != null && !StringUtils.isEmpty(style)) {
					for (int j = 0; j < dataList.size(); j++) {
						Map<String, Object> dataMap = dataList.get(j);
						boolean b = javaScriptScriptService.eval(condition.getScript(), dataMap);
						if (b) {
							String formatValue = styleMap.get(j + "_" + index);
							if (formatValue == null) {
								formatValue = "";
							}
							formatValue += style;
							styleMap.put(j + "_" + i, formatValue);
						}
					}
				}
			}
			
			for (int i = 0; i < fieldList.size(); i++) {
				Field field = fieldList.get(i);
				Column column = table.getColumnByColumnName(field.getColumnName());
				LookupInfo lookupInfo = column.getLookupInfo();
				if (lookupInfo != null) {
					if (lookupInfo.getDataSourceConfig() != null) {
						List<Map<String, Object>> dataList = tableData.getData();
						Set<Object> keyValueSet = new HashSet<Object>();
						for (int k = 0; k < dataList.size(); k++) {
							Object value = (Object) dataList.get(k).get(field.getColumnName());
							if (value != null) {
								keyValueSet.add(value);
							}
						}
						if (keyValueSet.size() == 0) {
							continue;
						}
						List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo,
								keyValueSet);
						if (selectItemList != null) {
							selectItemMap.put(field.getColumnName(), selectItemList);
						}
					} else {
						List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo);
						if (selectItemList != null) {
							selectItemMap.put(field.getColumnName(), selectItemList);
						}
					}
				}
			}
			List<Map<String, Object>> dataList = tableData.getData();
			for (int i = 0; i < dataList.size(); i++) {
				Map<String, Object> dataMap = dataList.get(i);
				for (int j = 0; j < fieldList.size(); j++) {
					Field field = fieldList.get(j);
					Column column = table.getColumnByColumnName(field.getColumnName());
					Object value = dataMap.get(field.getColumnName());
					if (value != null) {
						List<SelectItem> selectItemList = selectItemMap.get(field.getColumnName());
						if (selectItemList != null) {
							for (int k = 0; k < selectItemList.size(); k++) {
								if (selectItemList.get(k).getValue().equals(value)) {
									dataMap.put(field.getColumnName(), selectItemList.get(k).getName());
									break;
								}
							}
						}
					}
					if (column.getDataType().equals("boolean")) {
						if ("1".equals(value)) {
							dataMap.put(field.getColumnName(), true);
						} else {
							dataMap.put(field.getColumnName(), false);
						}
					} else {
						if (value != null) {
							if(column.getDataType().equals("datetime")) {
								IConverter converter=converterStore.getConverter("datetime");
								String sValue=converter.convertObjectToString(value);
								dataMap.put(field.getColumnName(), sValue);
							}else if(column.getDataType().equals("date")) {
								IConverter converter=converterStore.getConverter("date");
								String sValue=converter.convertObjectToString(value);
								dataMap.put(field.getColumnName(), sValue);
							}else if(column.getDataType().equals("time")) {
								IConverter converter=converterStore.getConverter("time");
								String sValue=converter.convertObjectToString(value);
								dataMap.put(field.getColumnName(), sValue);
							}
						}
					}
				}
			}
		}
		return detailReportData;
	}

	private TableData getTableData(YunContext yunContext, DetailReport detailReport,int page) {
		DataSourceConfig dataSourceConfig = detailReport.getDataSourceConfig();
		Query query = new Query();
		query.setPage(page);
		query.setLimit(10);
		Expression whereClauseExpression=dataSourceConfig.getWhereClause();
		if(whereClauseExpression!=null) {
			String whereClause=javaScriptScriptService.eval(whereClauseExpression.getScript(), yunContext.getVarValueMap());
			if(!StringUtils.isEmpty(whereClause)) {
				query.add(Restrictions.sql(whereClause));
			}
		}
		Page pageComponent=yunContext.getPage();
		if(pageComponent!=null) {
			List<IDataBinding> searchDataBindingList=pageComponent.getAttribute("key_search_field_list");
			if(searchDataBindingList!=null) {
				for(int i=0;i<searchDataBindingList.size();i++) {
					IDataBinding dataBinding=searchDataBindingList.get(i);
					Object value=variableService.getVariableValue(yunContext, ((IVarName)dataBinding).getVarName());
					if(value!=null) {
						String field=null;
						String op=null;
						String fieldInfos=pageComponent.getPageContext("field_"+dataBinding.getDataField());
						if(!StringUtils.isEmpty(fieldInfos)) {
							String fieldInfoArray[]=fieldInfos.split("[|]");
							field=fieldInfoArray[0];
							op=fieldInfoArray[1];
						}else {
							field=dataBinding.getDataField();
							op="=";
						}
						if(op.equals("=")) {
							query.add(Restrictions.eq(field, value));
						}else if(op.equals(">")) {
							query.add(Restrictions.gt(field, value));
						}else if(op.equals(">=")) {
							query.add(Restrictions.ge(field, value));
						}else if(op.equals("<")) {
							query.add(Restrictions.lt(field, value));
						}else if(op.equals("<=")) {
							query.add(Restrictions.le(field, value));
						}
					}
				}
			}
		}
		Table table = tableStore.get(dataSourceConfig.getTableName());
		IDataSource dataSource = dataSourceStore.getDataSource(table.getAccessType());
		TableData tableData = dataSource.select(yunContext, table, query);
		
		return tableData;
	}
}
